﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Ubatic.Common.Dto;
using System.Transactions;
using Ubatic.Business.Managers;
using Ubatic.Contracts.Services;
using Ubatic.Contracts.Contracts;
using Ubatic.Contracts;
using Ubatic.EvaluacionProyectos.Data;
using Ubatic.Contracts.Search;

namespace Ubatic.Business.Services
{
    public class AdminProyectoService : IAdminProyectoService
    {
        public List<Proyecto> GetProyectos(ServiceOptions options, SearchProyecto searchParams)
        {
            using (CitepEvaluacionProyectosEntities ctx = new CitepEvaluacionProyectosEntities())
            {
                IQueryable<DbProyecto> query = ctx.DbProyecto;

                if (String.IsNullOrEmpty(searchParams.Titulo))
                {
                    query = query.Where(p => p.Titulo.Contains(searchParams.Titulo));
                }

                if (searchParams.CreadorId.HasValue)
                {
                    query = query.Where(p => p.CreadorDeProyectoId == searchParams.CreadorId.Value);
                }

                var dbProyectoList = query.Select(p => p).ToList();
                List<Proyecto> proyectoList = new List<Proyecto>();
                foreach (var dbProyecto in dbProyectoList)
                {
                    proyectoList.Add(GetProyectoDatosGeneralesFromDbProyecto(dbProyecto));
                }

                return proyectoList;
            }
        }

        public Proyecto SaveProyectoDatosGenerales(Proyecto proyecto)
        {
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CitepEvaluacionProyectosEntities ctx = new CitepEvaluacionProyectosEntities())
                {
                    DbProyecto dbProyecto = ctx.DbProyecto.Where(p => p.Id == proyecto.Id).SingleOrDefault();

                    if (dbProyecto == null)
                    {
                        dbProyecto = new DbProyecto();
                        ctx.DbProyecto.AddObject(dbProyecto);
                    }

                    SetProyectoDatosGeneralesFromProyectoToDbProyecto(ctx, proyecto, dbProyecto);

                    ctx.SaveChanges();
                    tScope.Complete();
                    proyecto.Id = dbProyecto.Id;
                }
            }

            return proyecto;
        }

        public ProyectoEquipo SaveProyectoEquipo(ProyectoEquipo proyecto)
        {
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CitepEvaluacionProyectosEntities ctx = new CitepEvaluacionProyectosEntities())
                {
                    DbProyecto dbProyecto = ctx.DbProyecto.Where(p => p.Id == proyecto.Id).SingleOrDefault();

                    if (dbProyecto == null)
                    {
                        dbProyecto = new DbProyecto();
                        ctx.DbProyecto.AddObject(dbProyecto);
                    }

                    SetProyectoEquipoFromProyectoToDbProyecto(ctx, proyecto, dbProyecto);

                    ctx.SaveChanges();                    
                    tScope.Complete();
                    proyecto.Id = dbProyecto.Id;
                }
            }

            return proyecto;
        }

        public ProyectoMiembro SaveProyectoMiembroEquipo(ProyectoMiembro miembro)
        {
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CitepEvaluacionProyectosEntities ctx = new CitepEvaluacionProyectosEntities())
                {
                    DbProyectoMiembro dbProyectoMiembro = ctx.DbProyectoMiembro.Where(p => p.Id == miembro.Id).SingleOrDefault();

                    if (dbProyectoMiembro == null)
                    {
                        dbProyectoMiembro = new DbProyectoMiembro();
                        ctx.DbProyectoMiembro.AddObject(dbProyectoMiembro);
                    }

                    SetProyectoEquipoFromProyectoMiembroToDbProyectoMiembro(ctx, miembro, dbProyectoMiembro);                    

                    ctx.SaveChanges();

                    if (dbProyectoMiembro.UsuarioId.HasValue)
                    {
                        dbProyectoMiembro.Usuario.CUIL = miembro.CUIL;
                    }

                    ctx.SaveChanges();

                    tScope.Complete();
                    miembro.Id = dbProyectoMiembro.Id;
                }
            }

            return miembro;
        }

        public void EliminarProyecto(int proyectoId)
        {
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CitepEvaluacionProyectosEntities ctx = new CitepEvaluacionProyectosEntities())
                {
                    var dbProyecto = ctx.DbProyecto.Where(p => p.Id == proyectoId).Single();
                    ctx.DbProyecto.DeleteObject(dbProyecto);
                    ctx.SaveChanges();
                    tScope.Complete();
                }
            }
        }

        public void EliminarProyectoMiembro(int miembroId)
        {
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CitepEvaluacionProyectosEntities ctx = new CitepEvaluacionProyectosEntities())
                {
                    var dbProyectoMiembro = ctx.DbProyectoMiembro.Where(p => p.Id == miembroId).Single();
                    ctx.DbProyectoMiembro.DeleteObject(dbProyectoMiembro);
                    ctx.SaveChanges();
                    tScope.Complete();
                }
            }
        }

        public Proyecto GetProyecto(ServiceOptions options, int proyectId)
        {
            using (CitepEvaluacionProyectosEntities ctx = new CitepEvaluacionProyectosEntities())
            {
                IQueryable<DbProyecto> query = ctx.DbProyecto.Where(p => p.Id == proyectId);

                var dbProyecto = query.Select(p => p).Single();
                return GetProyectoDatosGeneralesFromDbProyecto(dbProyecto);
            }
        }

        private Proyecto GetProyectoDatosGeneralesFromDbProyecto(DbProyecto dbProyecto)
        {
            Proyecto proyecto = new Proyecto();
            proyecto.Id = dbProyecto.Id;
            proyecto.Titulo = dbProyecto.Titulo;
            proyecto.Presentacion = dbProyecto.Presentacion;
            proyecto.LineaDetrabajoId = dbProyecto.LineaDeTrabajoId;

            proyecto.ConvocatoriaId = dbProyecto.Convocatoria.Id;
            proyecto.ConvocatoriaNombre = dbProyecto.Convocatoria.Nombre;

            proyecto.CreadorDelProyectoId = dbProyecto.CreadorDeProyectoId.Value;
            proyecto.CreadorDelProyectoNombreYApellido = dbProyecto.Usuario.Nombre + " " + dbProyecto.Usuario.Apellido;

            proyecto.UnidadesAcademicasIds = new List<int>();
            foreach (var dbua in dbProyecto.UnidadAcademica)
            {
                proyecto.UnidadesAcademicasIds.Add(dbua.Id);
            }

            proyecto.AreaDeConocimientoIds = new List<int>();
            foreach (var ac in dbProyecto.AreaDeConocimiento)
            {
                proyecto.AreaDeConocimientoIds.Add(ac.Id);
            }

            proyecto.AsignaturasIds = new List<int>();
            foreach (var a in dbProyecto.ProyectoAsignatura)
            {
                proyecto.AsignaturasIds.Add(a.AsignaturaId);
            }


            proyecto.CargoId = dbProyecto.CargoId;

            proyecto.CargoDedicacionId = dbProyecto.CargoDedicacionId;

            proyecto.CargoCondicionId = dbProyecto.CargoCondicionId;

            proyecto.TipoDeCargoId = dbProyecto.TipoCargoId;

            return proyecto;
        }

        private void SetProyectoDatosGeneralesFromProyectoToDbProyecto(CitepEvaluacionProyectosEntities ctx, Proyecto proyecto, DbProyecto dbProyecto)
        {

            // TODO: faltan los tagas
            dbProyecto.Titulo = proyecto.Titulo;
            dbProyecto.Presentacion = proyecto.Presentacion;
            dbProyecto.ConvocatoriaId = proyecto.ConvocatoriaId;
            dbProyecto.LineaDeTrabajoId = proyecto.LineaDetrabajoId;

            dbProyecto.UnidadAcademica.Clear(); // Elimino las que no van y agrego las nuevas
            List<DbUnidadAcademica> nuevasUnidadesAcademicas = ctx.DbUnidadAcademica.Where(u => proyecto.UnidadesAcademicasIds.Contains(u.Id)).ToList();
            nuevasUnidadesAcademicas.ForEach(u => dbProyecto.UnidadAcademica.Add(u));

            dbProyecto.AreaDeConocimiento.Clear();
            List<DbAreaDeConocimiento> nuevasAreasDeConocimiento = ctx.DbAreaDeConocimiento.Where(a => proyecto.AreaDeConocimientoIds.Contains(a.Id)).ToList();
            nuevasAreasDeConocimiento.ForEach(a => dbProyecto.AreaDeConocimiento.Add(a));

            // TODO: Cuando agreguemos matricula hay que cambiar esto
            dbProyecto.ProyectoAsignatura.Clear();
            proyecto.AsignaturasIds.ForEach(a => dbProyecto.ProyectoAsignatura.Add(new DbProyectoAsignatura() { AsignaturaId = a }));

            dbProyecto.CreadorDeProyectoId = proyecto.CreadorDelProyectoId;

            dbProyecto.CargoId = proyecto.CargoId;

            dbProyecto.CargoDedicacionId = proyecto.CargoDedicacionId;

            dbProyecto.CargoCondicionId = proyecto.CargoCondicionId;

            dbProyecto.TipoCargoId = proyecto.TipoDeCargoId;

        }

        public ProyectoEquipo GetProyectoEquipo(ServiceOptions options, int proyectId)
        {
            using (CitepEvaluacionProyectosEntities ctx = new CitepEvaluacionProyectosEntities())
            {
                IQueryable<DbProyecto> query = ctx.DbProyecto.Where(p => p.Id == proyectId);

                var dbProyecto = query.Select(p => p).Single();
                return GetProyectoEquipoFromDbProyecto(dbProyecto);
            }
        }

        private ProyectoEquipo GetProyectoEquipoFromDbProyecto(DbProyecto dbProyecto)
        {
            ProyectoEquipo proyecto = new ProyectoEquipo();
            proyecto.Id = dbProyecto.Id;
            proyecto.Individual = dbProyecto.EsIndividual;

            proyecto.ExpEquipoEspecificaEnTIC = dbProyecto.ExpDelEquipo;

            foreach (DbExperienciaEnProdMaterialesEducativos exp in dbProyecto.ExperienciaEnProdMaterialesEducativos)
            {
                proyecto.ExpEquipoEspecificaEnTICTipada.Add(exp.Id);
            }

            proyecto.ExpEquipoEspecificaEnTICTipadaOtra = dbProyecto.ProyectoExpDelEquipoOtro;

            proyecto.EquiposRelacionados = dbProyecto.OtrosEquiposRelacionados;

            //proyecto.Miembros = GetMiembrosEquipoDelProyecto(dbProyecto.Id);

            return proyecto;
        }

        private void SetProyectoEquipoFromProyectoToDbProyecto(CitepEvaluacionProyectosEntities ctx, ProyectoEquipo proyecto, DbProyecto dbProyecto)
        {
            // TODO: faltan los tagas
            dbProyecto.EsIndividual = proyecto.Individual;
            dbProyecto.ExpDelEquipo = proyecto.ExpEquipoEspecificaEnTIC;

            dbProyecto.ExperienciaEnProdMaterialesEducativos.Clear();
            List<DbExperienciaEnProdMaterialesEducativos> nuevaExperiencia = ctx.DbExperienciaEnProdMaterialesEducativos.Where(e => proyecto.ExpEquipoEspecificaEnTICTipada.Contains(e.Id)).ToList();
            foreach (DbExperienciaEnProdMaterialesEducativos exp in nuevaExperiencia)
            {
                dbProyecto.ExperienciaEnProdMaterialesEducativos.Add(exp);
            }

            dbProyecto.ProyectoExpDelEquipoOtro = proyecto.ExpEquipoEspecificaEnTICTipadaOtra;

            dbProyecto.OtrosEquiposRelacionados = proyecto.EquiposRelacionados;           
        }

        public List<ProyectoMiembro> GetMiembrosEquipoDelProyecto(int proyectoId)
        {
            List<ProyectoMiembro> miembros = new List<ProyectoMiembro>();
            using (CitepEvaluacionProyectosEntities ctx = new CitepEvaluacionProyectosEntities())
            {
                IQueryable<DbProyecto> query = ctx.DbProyecto.Where(p => p.Id == proyectoId);

                var dbProyecto = query.Select(p => p).Single();

                foreach (DbProyectoMiembro dbMiembro in dbProyecto.ProyectoMiembro)
                {
                    miembros.Add(GetProyectoEquipoFromDbMiembro(dbMiembro));
                }
            }

            return miembros;
        }

        public ProyectoMiembro GetMiembroEquipo(ServiceOptions options, int miembroId)
        {
            ProyectoMiembro miembro = new ProyectoMiembro();
            using (CitepEvaluacionProyectosEntities ctx = new CitepEvaluacionProyectosEntities())
            {
                IQueryable<DbProyectoMiembro> query = ctx.DbProyectoMiembro.Where(p => p.Id == miembroId);

                var dbMiembro = query.Select(p => p).SingleOrDefault();

                if (dbMiembro != null)
                {
                    miembro = GetProyectoEquipoFromDbMiembro(dbMiembro);
                }
            }

            return miembro;
        }

        public ProyectoMiembro GetMiembroEquipoByEmail(ServiceOptions options, int proyectoId, string email)
        {
            ProyectoMiembro miembro = null;
            using (CitepEvaluacionProyectosEntities ctx = new CitepEvaluacionProyectosEntities())
            {
                var dbMiembro = (from u in ctx.DbUsuario
                                 join pm in ctx.DbProyectoMiembro on u.Id equals pm.UsuarioId
                                 where u.Email == email
                                 && pm.ProyectoId == proyectoId
                                 select pm).SingleOrDefault();

                if (dbMiembro != null)
                {
                    miembro = GetProyectoEquipoFromDbMiembro(dbMiembro);
                }
                else
                {
                    var dbUsuario = ctx.DbUsuario.Where(u => u.Email == email).SingleOrDefault();
                    if (dbUsuario != null)
                    {
                        miembro = new ProyectoMiembro();
                        miembro.ProyectoId = proyectoId;
                        miembro.UsuarioId = dbUsuario.Id;
                        miembro.NombreYApellido = dbUsuario.Nombre + " " + dbUsuario.Apellido;
                        miembro.Email = dbUsuario.Email;
                        miembro.CUIL = dbUsuario.CUIL;
                    }
                    else
                    {
                        // si el usuario no existe no se puede agregar al proyecto, el miembro queda en null
                    }
                }
            }

            return miembro;
        }

        public ProyectoMiembro GetProyectoEquipoFromDbMiembro(DbProyectoMiembro dbMiembro)
        {
            ProyectoMiembro miembro = new ProyectoMiembro();
            miembro.Id = dbMiembro.Id;
            miembro.ProyectoId = dbMiembro.ProyectoId;
            miembro.UsuarioId = dbMiembro.UsuarioId;
            miembro.UnidadAcademicaId = dbMiembro.UnidadAcademicaId;
            miembro.CargoDedicacionId = dbMiembro.CargoDedicacionId;
            miembro.CargoId = dbMiembro.CargoId;
            miembro.RolEnProyectoId = dbMiembro.RolEnProyectoId;            

            if (dbMiembro.UsuarioId.HasValue)
            {
                miembro.NombreYApellido = dbMiembro.Usuario.Nombre + " " + dbMiembro.Usuario.Apellido;
                miembro.Email = dbMiembro.Usuario.Email;
                miembro.CUIL = dbMiembro.Usuario.CUIL;
            }

            return miembro;
        }

        private void SetProyectoEquipoFromProyectoMiembroToDbProyectoMiembro(CitepEvaluacionProyectosEntities ctx, ProyectoMiembro miembro, DbProyectoMiembro dbMiembro)
        {           
            dbMiembro.Id =  miembro.Id;
            dbMiembro.ProyectoId = miembro.ProyectoId;
            dbMiembro.UsuarioId = miembro.UsuarioId;
            dbMiembro.UnidadAcademicaId = miembro.UnidadAcademicaId;
            dbMiembro.CargoDedicacionId = miembro.CargoDedicacionId;
            dbMiembro.CargoId =  miembro.CargoId;
            dbMiembro.RolEnProyectoId = miembro.RolEnProyectoId;                     
        }

        public List<MaestroBase> GetConvocatorias()
        {
            using (CitepEvaluacionProyectosEntities ctx = new CitepEvaluacionProyectosEntities())
            {
                return (from l in ctx.DbConvocatoria
                        orderby l.Nombre
                        select new MaestroBase()
                        {
                            Id = l.Id,
                            Nombre = l.Nombre
                        }).ToList();
            }
        }

        public List<MaestroBase> GetLineasDeTrabajo()
        {
            using (CitepEvaluacionProyectosEntities ctx = new CitepEvaluacionProyectosEntities())
            {
                return (from l in ctx.DbLineaDeTrabajo
                        orderby l.Nombre
                        select new MaestroBase()
                        {
                            Id = l.Id,
                            Nombre = l.Nombre
                        }).ToList();
            }
        }

        public List<MaestroBase> GetUnidadesAcademicas()
        {
            using (CitepEvaluacionProyectosEntities ctx = new CitepEvaluacionProyectosEntities())
            {
                return (from l in ctx.DbUnidadAcademica
                        orderby l.Nombre
                        select new MaestroBase()
                        {
                            Id = l.Id,
                            Nombre = l.Nombre
                        }).ToList();
            }
        }

        public List<MaestroBase> GetAreasDeConocimiento()
        {
            using (CitepEvaluacionProyectosEntities ctx = new CitepEvaluacionProyectosEntities())
            {
                return (from l in ctx.DbAreaDeConocimiento
                        orderby l.Nombre
                        select new MaestroBase()
                        {
                            Id = l.Id,
                            Nombre = l.Nombre
                        }).ToList();
            }
        }

        public List<MaestroBase> GetAsignaturas()
        {
            using (CitepEvaluacionProyectosEntities ctx = new CitepEvaluacionProyectosEntities())
            {
                return (from l in ctx.DbAsignatura
                        orderby l.Nombre
                        select new MaestroBase()
                        {
                            Id = l.Id,
                            Nombre = l.Nombre
                        }).ToList();
            }
        }

        public List<MaestroBaseCargo> GetCargos()
        {
            using (CitepEvaluacionProyectosEntities ctx = new CitepEvaluacionProyectosEntities())
            {
                return (from l in ctx.DbCargo
                        orderby l.Nombre
                        select new MaestroBaseCargo()
                        {
                            Id = l.Id,
                            Nombre = l.Nombre
                        }).ToList();
            }
        }

        public List<MaestroBaseCargo> GetCargoDedicaciones()
        {
            using (CitepEvaluacionProyectosEntities ctx = new CitepEvaluacionProyectosEntities())
            {
                return (from l in ctx.DbCargoDedicacion
                        orderby l.Nombre
                        select new MaestroBaseCargo()
                        {
                            Id = l.Id,
                            Nombre = l.Nombre
                        }).ToList();
            }
        }

        public List<MaestroBaseCargo> GetTipoDeCargo()
        {
            using (CitepEvaluacionProyectosEntities ctx = new CitepEvaluacionProyectosEntities())
            {
                return (from l in ctx.DbTipoCargo
                        orderby l.Nombre
                        select new MaestroBaseCargo()
                        {
                            Id = l.Id,
                            Nombre = l.Nombre
                        }).ToList();
            }
        }

        public List<MaestroBaseCargo> GetCargoCondicion()
        {
            using (CitepEvaluacionProyectosEntities ctx = new CitepEvaluacionProyectosEntities())
            {
                return (from l in ctx.DbCargoCondicion
                        orderby l.Nombre
                        select new MaestroBaseCargo()
                        {
                            Id = l.Id,
                            Nombre = l.Nombre
                        }).ToList();
            }
        }

        public List<MaestroBase> GetExperienciaEnTIC()
        {
            using (CitepEvaluacionProyectosEntities ctx = new CitepEvaluacionProyectosEntities())
            {
                return (from l in ctx.DbExperienciaEnProdMaterialesEducativos
                        orderby l.Nombre
                        select new MaestroBase()
                        {
                            Id = l.Id,
                            Nombre = l.Nombre
                        }).ToList();
            }
        }

        public List<MaestroBase> GetRolEnProyecto()
        {
            using (CitepEvaluacionProyectosEntities ctx = new CitepEvaluacionProyectosEntities())
            {
                return (from l in ctx.DbRolEnProyecto
                        orderby l.Nombre
                        select new MaestroBase()
                        {
                            Id = l.Id,
                            Nombre = l.Nombre
                        }).ToList();
            }
        }
    }
}
